package com.kongjs.application.service;

import com.kongjs.application.properties.FileCopyProperties;
import com.kongjs.application.properties.MavenConfigProperties;
import com.kongjs.application.properties.MavenProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.shared.invoker.*;
import org.apache.maven.shared.utils.cli.CommandLineException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class MavenOperationService {

    private final MavenProperties mavenProperties;
    private final Map<String, MavenConfigProperties> mavenConfigMap = new ConcurrentHashMap<>();
    private final Map<String, InvocationRequest> invocationRequestMap = new ConcurrentHashMap<>();

    public MavenOperationService(MavenProperties mavenProperties) {
        this.mavenProperties = mavenProperties;
        this.init();
    }

    private void init() {
        List<MavenConfigProperties> configs = mavenProperties.getConfigs();
        for (MavenConfigProperties config : configs) {
            mavenConfigMap.put(config.getId(), config);
            InvocationRequest request = getInvocationRequest(config);
            invocationRequestMap.put(config.getId(), request);
        }
    }

    public InvocationRequest getInvocationRequest(MavenConfigProperties properties) {
        InvocationRequest request = new DefaultInvocationRequest();

        request.setJavaHome(new File(properties.getJavaHome()));
        request.setMavenHome(new File(properties.getMavenHome()));
        request.setLocalRepositoryDirectory(new File(properties.getLocalRepository()));

        if (StringUtils.hasText(properties.getGlobalSettings())) {
            request.setGlobalSettingsFile(new File(properties.getGlobalSettings()));
        }
        if (StringUtils.hasText(properties.getGlobalToolchains())) {
            request.setGlobalToolchainsFile(new File(properties.getGlobalToolchains()));
        }
        if (StringUtils.hasText(properties.getUserSettings())) {
            request.setUserSettingsFile(new File(properties.getUserSettings()));
        }
        if (StringUtils.hasText(properties.getToolchains())) {
            request.setToolchainsFile(new File(properties.getToolchains()));
        }

        request.addArgs(properties.getArgs());

        if (!CollectionUtils.isEmpty(properties.getProfiles())) {
            request.setProfiles(properties.getProfiles());
        }

        if (!CollectionUtils.isEmpty(properties.getProjects())) {
            request.setProjects(properties.getProjects());
        }

        request.setBaseDirectory(new File(properties.getWorkingDirectory()));

        request.setBatchMode(true);
        request.setShowErrors(true);
        request.setShowVersion(true);
        request.setAlsoMake(true);
        request.setAlsoMakeDependents(true);
        request.setOutputHandler(new PrintStreamHandler());
        request.setErrorHandler(new PrintStreamHandler());

        return request;
    }

    public void pack(String id) {
        InvocationRequest request = invocationRequestMap.get(id);
        Invoker invoker = new DefaultInvoker();
        InvocationResult result;
        try {
            result = invoker.execute(request);
        } catch (MavenInvocationException e) {
            throw new RuntimeException(e);
        }
        try {
            if (result.getExecutionException() != null) {
                throw result.getExecutionException();
            }
        } catch (CommandLineException e) {
            throw new RuntimeException(e);
        }
        if (result.getExitCode() != 0) {
            throw new RuntimeException();
        }
        MavenConfigProperties properties = mavenConfigMap.get(id);
        List<FileCopyProperties> fileCopy = properties.getFileCopy();
        for (FileCopyProperties copyProperties : fileCopy) {
            copy(properties.getWorkingDirectory(), properties.getDeployDirectory(), copyProperties);
        }
    }

    private void copy(String sourceRootDir, String targetRootDir, FileCopyProperties copyProperties) {
        String sourceDir = copyProperties.getSourceDir();
        String sourceFile = copyProperties.getSourceFile();
        String targetDir = copyProperties.getTargetDir();
        String targetFile = copyProperties.getTargetFile();
        if (!StringUtils.hasText(sourceDir) || !StringUtils.hasText(targetDir)) {
            return;
        }
        // 文件copy
        if (StringUtils.hasText(sourceFile) && StringUtils.hasText(targetFile)) {
            Path source = Path.of(sourceRootDir, sourceDir, sourceFile);
            Path target = Path.of(targetRootDir, targetDir, targetFile);
            log.info("copyFile {} {}", source, target);
            try {
                if (!Files.isDirectory(target.getParent()) && Files.notExists(target.getParent())) {
                    Files.createDirectories(target.getParent());
                }
                FileCopyUtils.copy(source.toFile(), target.toFile());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        // 目录copy
        if (!StringUtils.hasText(sourceFile) && !StringUtils.hasText(targetFile)) {
            Path source = Path.of(sourceRootDir, sourceDir);
            Path target = Path.of(targetRootDir, targetDir);
            log.info("copyDirectory {} {}", source, target);
            try {
                if (!Files.isDirectory(target) && Files.notExists(target)) {
                    Files.createDirectories(target);
                }
                FileSystemUtils.copyRecursively(source, target);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
